import _ from 'lodash'
import ReactDOM from 'react-dom'
import React from 'react'
import { http, udConfigProvider } from '..'
import { IUaaOriginLoginInfo, IUaaMenu, IUaaAppInfo, IUaaAppStartOptions, IRouteItem, IMenuItem, IUaaTokenData } from '../types'

class UaaApp {

  private listens: IListen = {}
  public options: IUaaAppStartOptions = {} as IUaaAppStartOptions
  public functionLimits: Set<string> = new Set()

  /** 系统名称(会自动从uaa中的菜单获取) */
  public appName: string = ''
  /** 系统唯一标识 */
  public appCode: string = ''
  /** 管理中心(uaa)前端访问地址 */
  public centerUrl: string = ''

  /** 菜单表 */
  public menus: IMenuItem[] = []
  /** 路由表 */
  public routes: IRouteItem[] = []
  /** customId 和 routeitem 映射对象 */
  public routesMaps: { [key in string]: IRouteItem } = {}
  /** 账号初始密码 */
  public sysInitialPwd = 'Aa888888'

  /** 启动系统 */
  public start(opts: IUaaAppStartOptions) {
    this.processOptions(opts)
    this.processRoutes(this.routes)
    // this.subscribePostMessage()

    if (process.env.REACT_APP_ENV == 'local') {
      this.startFromLocal()
    } else {
      this.startFromServer()
    }
  }

  private startFromLocal() {
    let token = this.getToken()
    if (token == null) {
      let Login: any = this.options.loginComponent
      if (!Login) {
        Login = require('../ui/UdLocalLogin').default
      }
      ReactDOM.render(<Login {...this.options.local} />, document.getElementById('root'))
    } else {
      let sysInfo: IUaaOriginLoginInfo = {
        Authorization: token,
        urls: {},
        systemSelectKey: ''
      } as IUaaOriginLoginInfo
      if (this.options.local.useLocalMenu) {
        sysInfo.systemInfo = {
          generalMenus: [
            {
              application: this.appCode,
              items: this.options.local.menus,
              text: '本地数据'
            } as IUaaMenu
          ]
        } as IUaaAppInfo
      } else {
        let info = this.getSysInfo()
        if (info) {
          sysInfo.systemInfo = info
        } else {
          throw new Error('Storage UaaSysInfo 的值不合法。')
        }
      }
      this.startInner(sysInfo)
    }
  }

  private startFromServer() {
    let token = this.getToken()
    if (this.options.loginComponent&&!token) {
      let Login = this.options.loginComponent as any
      ReactDOM.render(<Login {...this.options} />, document.getElementById('root'))
    } else {
      /* let success = false
      setTimeout(() => {
        if (!success) {
          this.startFail()
        }
      }, 3000)
      this.sendMessage({ type: MessageTypes.GetOriginLoginInfo }, (data: IUaaOriginLoginInfo) => {
        if (data && data.Authorization && data.systemInfo) {
          success = true
          this.startInner(data)
        } else {
          console.log('启动时获取到的数据有误', data)
        }
      }) */
      let sysInfo: IUaaOriginLoginInfo = {
        Authorization: token,
        urls: {},
        systemSelectKey: ''
      } as IUaaOriginLoginInfo
      let info = this.getSysInfo()
      if (info) {
        sysInfo.systemInfo = info
      }
      this.startInner(sysInfo)
    }
  }

  private startInner(data: IUaaOriginLoginInfo) {
    let menus = data.systemInfo.generalMenus.find(n => n.application == this.appCode)
    if (menus == null) {
      if (process.env.NODE_ENV == 'development') {
        this.startFail(`找不到${this.appCode}的菜单定义，可能是菜单未上报或该账号没有权限。`)
      } else {
        this.startFail(`启动失败，很可能是你的账号没有访问该系统的权限。`)
      }
      return
    }
    this.appName = menus.text
    this.menus = this.transformMenus(menus.items)
    //*暂时屏蔽客户管理中奖品兑付
    let children = this.menus.find(item=>item.key==="user_customer")?.children ?? []
    if(children.length){
      this.menus.find(item=>item.key==="user_customer").children = children.filter(chid => !['dealer_prize'].includes(chid.key))
    }

    if (process.env.REACT_APP_ENV == 'local') {
      if (!this.options.local.apiBaseUrl) {
        http.defaults.baseURL = data.urls[this.appCode]
      }
    } else {
      this.setToken(data.Authorization)
      this.setSysInfo(data.systemInfo)
      // http.defaults.baseURL = data.urls[this.appCode]
    }

    window.setInterval(this.refreshToken.bind(this), 10 * 60 * 1000)

    this.options.success()
    setTimeout(() => { this.closeLoader() }, 100)
  }

  public startFail(text?: string): void {
    document.body.innerHTML = `<div class="ud-start-fail">${text || '启动失败'}</div>`
  }


  public processOptions(opts: IUaaAppStartOptions): void {
    this.options = opts
    if (this.options.autoMapMenu == null) {
      this.options.autoMapMenu = true
    }
    this.appCode = opts.appCode

    if (process.env.REACT_APP_ENV == 'local') {
      if (opts.local.apiBaseUrl) {
        http.defaults.baseURL = opts.local.apiBaseUrl
      }
    } else if (process.env.REACT_APP_ENV == 'dev') {
      http.defaults.baseURL = 'http://10.0.48.27:9999'
    } else if (process.env.REACT_APP_ENV == 'testIp') {
      http.defaults.baseURL = 'http://10.0.48.28:9999'
    } else if (process.env.REACT_APP_ENV == 'test') {
      http.defaults.baseURL = 'http://10.0.48.28:9999'
      //http.defaults.baseURL = 'https://jxsmhtest03.lzlj.com'
    } else if (process.env.REACT_APP_ENV == 'uat') {
      http.defaults.baseURL = 'http://10.0.33.87:9999'
    } else if (process.env.REACT_APP_ENV == 'prod') {
      http.defaults.baseURL = 'https://jxsmh-gateway.lzlj.com'
    }
    this.routes = opts.routes
  }

  public processRoutes(routes: IRouteItem[]): void {

    const recursion = (routes: IRouteItem[], paths: string[] = []) => {
      for (const item of routes) {
        if (item.customId) {
          if (_.isArray(item.customId)) {
            for (const id of item.customId) {
              this.routesMaps[id] = item
            }
          } else {
            this.routesMaps[item.customId] = item
          }
        }
        let hasChildren = _.isArray(item.children) && item.children.length > 0
        if (hasChildren) {
          recursion(item.children, paths)
        }
      }
    }

    recursion(routes)
  }

  public transformMenus(old: IUaaMenu[]): IMenuItem[] {
    let res: IMenuItem[] = []
    let recursion = (items: IUaaMenu[], parentMenu?: IMenuItem): IMenuItem[] => {
      if (!_.isArray(items) || items.length == 0) {
        return []
      }
      let menus: IMenuItem[] = []
      for (const item of items) {
        let isMenu = item.type == 'GROUP' || item.type == 'INNER_LINK'
        if (process.env.REACT_APP_ENV == 'local') {
          if (this.options.local.useLocalMenu) {
            isMenu = true
          }
        }
        if (isMenu) {
          let menu: IMenuItem = this.transformMenu.call(this, item)
          if (this.options.autoMapMenu) {
            if (this.routesMaps[item.customId]) {

              menu.path = this.routesMaps[item.customId].path as string
            } else {
              if (process.env.NODE_ENV == 'development') {
                console.error(`没有找到菜单${item.text} - ${item.customId}，所对应的路由。`)
              }
            }
          }
          menu.children = recursion(item.items, menu)
          menus.push(menu)
        }
        if (item.type == 'RESOURCE_INNER_LINK') {
          if (!this.functionLimits.has(item.customId)) {
            this.functionLimits.add(item.customId)
          }
          if (this.routesMaps[item.customId] && parentMenu) {
            parentMenu.relevantPaths = parentMenu.relevantPaths || []
            parentMenu.relevantPaths.push(this.routesMaps[item.customId].path as string)
          }
        }
      }
      return menus
    }
    res = recursion(old)
    return res
  }

  public transformMenu(old: IUaaMenu): IMenuItem {
    let menu: IMenuItem = {
      key: old.customId,
      text: old.text,
      icon: old.icon,
      path: old.link
    }
    return menu
  }

  public refreshToken(): void {
    // TODO: 这里的逻辑需要修改
    // this.sendMessage({ type: MessageTypes.RefreshToken }, (res) => {
    //   this.setToken(res)
    // })
  }

  public setToken(obj?: IUaaTokenData): void {
    if (obj) {
      sessionStorage.setItem('Authorization', JSON.stringify(obj))
    } else {
      sessionStorage.removeItem('Authorization')
    }
  }

  public getToken(): IUaaTokenData | null {
    let json = sessionStorage.getItem('Authorization')
    if (json) {
      try {
        return JSON.parse(json) as IUaaTokenData
      } catch {
        return
      }
    }
    return
  }

  public getSysInfo(): IUaaAppInfo | null {
    let json = sessionStorage.getItem('UaaSysInfo')
    if (json) {
      try {
        return JSON.parse(json) as IUaaAppInfo
      } catch {
        return
      }
    }
    return
  }

  public setSysInfo(obj?: IUaaAppInfo): void {
    if (obj) {
      sessionStorage.setItem('UaaSysInfo', JSON.stringify(obj))
    } else {
      sessionStorage.removeItem('UaaSysInfo')
    }
  }

  public setIsInitialPwd(str?: string): void {
    if (str) {
      sessionStorage.setItem('isInitialPwd', str)
    } else {
      sessionStorage.removeItem('isInitialPwd')
    }
  }

  public isInitialPwd(): boolean {
    return sessionStorage.getItem('isInitialPwd') ? true : false
  }

  public signOut = () => {
    sessionStorage.clear()
    window.location.reload()
  }

  public closeLoader = (delay: number = 300) => {
    let loader = document.getElementById('loader')
    setTimeout(() => {
      if (loader) {
        loader.remove()
      }
    }, delay)
  }

  public canUse(key: string): boolean {
    if (_.isFunction(udConfigProvider.auth.canUse)) {
      return udConfigProvider.auth.canUse(key)
    }
    return this.functionLimits.has(key)
  }

  private subscribePostMessage(): void {
    if (this.centerUrl) {
      window.addEventListener('message', this.postMessageHandler)
      window.onhashchange = (e: HashChangeEvent) => {
        const hash = window.location.hash;
        if (hash !== '#/') {
          const message: IMessage = { type: MessageTypes.ChangeUrl, data: window.location.href }
          this.sendMessageToCenter(message)
        }
      }
    }
  }

  private sendMessage(message: IMessage, callback?: (data: any) => void): void {
    if (_.isFunction(callback)) {
      this.listens[message.type] = callback
    }
    this.sendMessageToCenter(message)
  }

  private postMessageHandler = (e: MessageEvent) => {
    const message = e.data
    const origin = e.origin || (e as any).originalEvent.origin
    if (this.listens[message.type]) {
      if (origin === this.centerUrl) {
        this.listens[message.type](message.data)
        delete this.listens[message.type]
      } else {
        console.warn(`message origin：${origin}和center url：${this.centerUrl} 不一致`)
      }
    }
  }

  private sendMessageToCenter(message: any) {
    try {
      window.parent.postMessage(message, this.centerUrl)
    } catch (e) {
      console.log('发送消息失败', e)
    }
  }

}


/**
 * 消息模型
 */
export interface IMessage {
  type: MessageTypes
  data?: any
}

/**
 * 消息类型
 */
export enum MessageTypes {
  /**
   * 刷新token
   */
  RefreshToken = 'ReFreshAuth',
  /** 
   * 获取token、权限等信息 
   */
  GetLoginInfo = 'LoginInfo',
  /**
   * 获取原始的token、权限等信息（和上面的数据结构不一样）
   */
  GetOriginLoginInfo = 'OriginLoginInfo',
  /**
   * 退出登录
   */
  LoginOut = 'LoginOut',
  /**
   * 子系统url地址发生改变
   */
  ChangeUrl = 'ChangeUrl'
}

interface IListen {
  [type: string]: (data: any) => void
}


const uaaApp = new UaaApp()

export { uaaApp }
